/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mips;

import componentes.basicos.*;
import componentes.mips.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

/**
 *
 * @author EvandroFBL
 */
public class mipsMulti {
    
    private PC pc;                          
    private Barramento IouD;              
    private FileWriter arquivoSaida;        
    private ArrayList<String> minemonicos;  
    private int clock = 0;    
    private MemoriaDados mem;
    private UnidadeControlePrincipal ucp;
    private ControleALU ctrlALU;
    private ALU aluu;
    private BancoDeRegistradores bancoReg;
    private Multiplexador muxpc;        
    private Multiplexador muxOrigPc;
    private Multiplexador muxRegDst;
    private Multiplexador muxMem2Reg;    
    private Multiplexador muxAluA;
    private Multiplexador muxAluB;
    private RegistradorInstrucao regInstrucao;
    private Registrador saidaALU;
    private Registrador regA;
    private Registrador regB;
    private Registrador mdr;    
    private String desv;
    private String extend;

    /**
     * Cria um MIPS passando um arquivo de instruções.
     * @param arqInstrucoes Arquivo que contém as instruções à serem processadas.
     * @throws Exception Gera uma exceção se o arquivo nao foi lido.
     */
    public mipsMulti(String arqInstrucoes) throws Exception {
        
        // Tenta ler o arquivo.
        try {
            arquivoSaida = new FileWriter(new File(arqInstrucoes.replaceAll(".txt", "_Saida.txt")));
        } catch (IOException ex) {
            Logger.getLogger(mipsMulti.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        //Criação dos componentes usados
        mem = new MemoriaDados(256);
        ucp = new UnidadeControlePrincipal();
        ctrlALU = new ControleALU();
        aluu = new ALU();
        bancoReg = new BancoDeRegistradores();
        muxpc = new Multiplexador();        
        muxOrigPc = new Multiplexador(4);
        muxRegDst = new Multiplexador();
        muxMem2Reg = new Multiplexador();
        muxAluA = new Multiplexador();
        muxAluB = new Multiplexador(4);
        regInstrucao = new RegistradorInstrucao();
        saidaALU = new Registrador();
        regA = new Registrador();
        regB = new Registrador();
        mdr = new Registrador();
        desv = new String();
        extend = new String();
        
        // Leitura das instrucoes, contidas em um arquivo.
        LeArquivoInstrucoes instrucoes = new LeArquivoInstrucoes(arqInstrucoes);
        instrucoes.readFile();
        
        // Armazena na lista de minemonicos, os minemonicos de cada instrucao.
        minemonicos = instrucoes.getMinemonicos();        
        
        // Cria um contador de Program
        pc = new PC();
        
        // Cria o barramento de origem ao PC
        IouD = new Barramento();        
    }
    
    public void Ciclo1(){     
        //passando o endereço do PC para memória.
        this.IouD.setBits(ucp.getIOuD().getPalavra());
        mem.setEndereco(pc.getSaida());
        
        //passando conteudo da memória para o registrador de instrução.
        if(regInstrucao.getSinalEscreveIR().getPalavra() == Constantes.OPERANTE){
            regInstrucao.setConteudo(mem.getDadosLeitura().getPalavra());
        }

        //calculo do PC + 4
        muxAluA.setSinalOpr(ucp.getOrigemALUA());
        ctrlALU.setOpALU(ucp.getOpALU());
        aluu.setEntrada1(muxAluA.getSaida());
        aluu.setEntrada2(new Barramento(Constantes.QUATRO));
        aluu.setSinalControle(new Barramento(new Palavra(Constantes.INOPERANTE.getPalavra())));
        aluu.setResultado();
        saidaALU.setConteudo(aluu.getResultado().getPalavra());
        muxOrigPc.setSinalOpr(ucp.getOrigemPC());
    }
    
    public void Ciclo2(){
        //passando os registradores para o banco de registradores
        Barramento bar = new Barramento();
        bar = regInstrucao.getSaida();
        String s = new String();
        s = bar.getSubBits(6, 10);
        s = "00000000000000000000000000" + s;
        bancoReg.setEntrada1(new Barramento(new Palavra(s)));
        regA.setConteudo(new Palavra(s));
        
        bar = regInstrucao.getSaida();
        s = bar.getSubBits(11, 15);
        s = "00000000000000000000000000" + s;
        bancoReg.setEntrada2(new Barramento(new Palavra(s)));
        regB.setConteudo(new Palavra(s));
        
        bar = regInstrucao.getSaida();
        s = bar.getSubBits(26, 31);
        ctrlALU.setFunct(new Barramento(new Palavra(s)));
        
        
        bar = regInstrucao.getSaida();
        s = bar.getSubBits(16, 31);
        desv = "00000000000000" + s + "00";
        extend = "0000000000000000" + s;
        
        
        //calculando o endereço do desvio condicional
        aluu.setEntrada1(pc.getSaida());
        aluu.setEntrada2(new Barramento(new Palavra(desv)));
        aluu.setSinalControle(new Barramento(new Palavra(Constantes.INOPERANTE.getPalavra())));
        aluu.setResultado();
        saidaALU.setConteudo(aluu.getResultado().getPalavra());        
    }
    
    public void Ciclo3(String[] minemonico){        
        //se a instrução for do tipo R
        if(minemonico.equals("add")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada1(regB.getSaida());
            aluu.setSinalControle(ctrlALU.getSaida());
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());
        }
        if(minemonico[0].equals("sub")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada1(regB.getSaida());
            aluu.setSinalControle(ctrlALU.getSaida());
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());     
        }
            
        if(minemonico[0].equals("and")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada1(regB.getSaida());
            aluu.setSinalControle(ctrlALU.getSaida());
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());    
        }
        if(minemonico[0].equals("or")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada1(regB.getSaida());
            aluu.setSinalControle(ctrlALU.getSaida());
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());    
        }
        if(minemonico[0].equals("slt")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada1(regB.getSaida());
            aluu.setSinalControle(ctrlALU.getSaida());
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());
        }     
        
        //se a instrução for LW
        if(minemonico.equals("lw")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada2(new Barramento(new Palavra(extend)));
            aluu.setSinalControle(new Barramento(new Palavra(Constantes.INOPERANTE.getPalavra())));
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());
            ucp.setSinais("LW");
        }
        
        //se a instrução for SW
        if(minemonico.equals("sw")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada2(new Barramento(new Palavra(extend)));
            aluu.setSinalControle(new Barramento(new Palavra(Constantes.INOPERANTE.getPalavra())));
            aluu.setResultado();
            saidaALU.setConteudo(aluu.getResultado().getPalavra());
            ucp.setSinais("SW");
        }
        //se a instrução for do tipo BEQ
        if(minemonico[0].equals("beq")){
            aluu.setEntrada1(regA.getSaida());
            aluu.setEntrada2(regB.getSaida());
            aluu.setSinalControle(new Barramento(new Palavra(Constantes.OPERANTE.getPalavra())));
            aluu.setResultado();
            if(aluu.getFlagZ() == 1){
                pc.setEntrada(saidaALU.getSaida());
            }//se o desvio for tomado, PC recebe o desvio... caso contrário, já está com o PC+4
            saidaALU.setConteudo(aluu.getResultado().getPalavra());
        }
        
        //se a instrução for do tipo J
        else{
            Barramento bar = new Barramento();
            bar = regInstrucao.getSaida();
            String s = new String();
            String sr = new String();
            s = bar.getSubBits(6, 31);
            s = s + "00";
            sr = pc.getSaida().getSubBits(0, 4);
            pc.setEntrada(new Barramento(new Palavra(sr + s)));
        }
    }
    
    public void Ciclo4(String tipo){
        //se for instrução do tipo R
        if(tipo.equals("R")){
            bancoReg.setBarDadosParaEscrita(saidaALU.getSaida());
        }
        
        //se for instrução LW
        mem.setEndereco(saidaALU.getSaida());
        mdr.setConteudo(mem.getDadosLeitura().getPalavra());
        
        //se for instrução SW
        mem.setEndereco(saidaALU.getSaida());
        mem.setDadosEscrita(regB.getSaida());       
    }
    
    public void Ciclo5(){
        //final da instrução de LW
        bancoReg.setBarDadosParaEscrita(mdr.getSaida());        
    }
}